package jp.seraph.jsade.core;

import java.util.HashMap;
import java.util.Map;

import jp.seraph.jsade.perceptor.SeeObject;
import jp.seraph.jsade.perceptor.SeeObjectConfidence;
import jp.seraph.jsade.perceptor.SeeObjectType;
import jp.seraph.jsade.perceptor.SeePerceptor;

public abstract class AbstractSeeObjectCalculator {
    public AbstractSeeObjectCalculator() {
        mCalcCache = new HashMap<SeeObjectType, SeeObject>();
        initMap();
    }

    private void initMap() {

        Map<SeeObjectType, SeeObjectCalculator> tMap = new HashMap<SeeObjectType, SeeObjectCalculator>();

        tMap.put(SeeObjectType.LEFT_FIELD_1, new SeeObjectCalculator() {
            public SeeObject calc(SeePerceptor aSeePerceptor) {
                return AbstractSeeObjectCalculator.this.calcLeftField1(aSeePerceptor);
            }
        });

        tMap.put(SeeObjectType.LEFT_FIELD_2, new SeeObjectCalculator() {
            public SeeObject calc(SeePerceptor aSeePerceptor) {
                return AbstractSeeObjectCalculator.this.calcLeftField2(aSeePerceptor);
            }
        });

        tMap.put(SeeObjectType.RIGHT_FIELD_1, new SeeObjectCalculator() {
            public SeeObject calc(SeePerceptor aSeePerceptor) {
                return AbstractSeeObjectCalculator.this.calcRightField1(aSeePerceptor);
            }
        });

        tMap.put(SeeObjectType.RIGHT_FIELD_2, new SeeObjectCalculator() {
            public SeeObject calc(SeePerceptor aSeePerceptor) {
                return AbstractSeeObjectCalculator.this.calcRightField2(aSeePerceptor);
            }
        });

        tMap.put(SeeObjectType.LEFT_GOAL_1, new SeeObjectCalculator() {
            public SeeObject calc(SeePerceptor aSeePerceptor) {
                return AbstractSeeObjectCalculator.this.calcLeftGoal1(aSeePerceptor);
            }
        });

        tMap.put(SeeObjectType.LEFT_GOAL_2, new SeeObjectCalculator() {
            public SeeObject calc(SeePerceptor aSeePerceptor) {
                return AbstractSeeObjectCalculator.this.calcLeftGoal2(aSeePerceptor);
            }
        });

        tMap.put(SeeObjectType.RIGHT_GOAL_1, new SeeObjectCalculator() {
            public SeeObject calc(SeePerceptor aSeePerceptor) {
                return AbstractSeeObjectCalculator.this.calcRightGoal1(aSeePerceptor);
            }
        });

        tMap.put(SeeObjectType.RIGHT_GOAL_2, new SeeObjectCalculator() {
            public SeeObject calc(SeePerceptor aSeePerceptor) {
                return AbstractSeeObjectCalculator.this.calcRightGoal2(aSeePerceptor);
            }
        });

        mPositionCalculatorMap = tMap;
    }

    private Map<SeeObjectType, SeeObjectCalculator> mPositionCalculatorMap;

    private Map<SeeObjectType, SeeObject> mCalcCache;

    public SeeObject calcSeeObject(SeeObjectType aType, SeePerceptor aPerceptor) {
        SeeObject tResult = mCalcCache.get(aType);

        if (tResult == null) {
            SeeObjectCalculator tCalculator = mPositionCalculatorMap.get(aType);
            if (tCalculator == null)
                return new SeeObject(aType, SeeObjectConfidence.Unpredictable, 0, 0, 0);
            tResult = tCalculator.calc(aPerceptor);
            mCalcCache.put(aType, tResult);
        }

        return tResult;
    }

    public void reset() {
        mCalcCache.clear();
    }

    protected abstract SeeObject calcRightField1(SeePerceptor aSeePerceptor);

    protected abstract SeeObject calcRightField2(SeePerceptor aSeePerceptor);

    protected abstract SeeObject calcLeftField1(SeePerceptor aSeePerceptor);

    protected abstract SeeObject calcLeftField2(SeePerceptor aSeePerceptor);

    protected abstract SeeObject calcLeftGoal1(SeePerceptor aSeePerceptor);

    protected abstract SeeObject calcLeftGoal2(SeePerceptor aSeePerceptor);

    protected abstract SeeObject calcRightGoal1(SeePerceptor aSeePerceptor);

    protected abstract SeeObject calcRightGoal2(SeePerceptor aSeePerceptor);

    private static interface SeeObjectCalculator {
        public SeeObject calc(SeePerceptor aSeePerceptor);
    }
}
